/*
 Developer: John Archer (john.archer.jpa@gmail.com)
 
 This file is part of VTBuilder.

 VTBuilder is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License.

 VTBuilder is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with VTBuilder.  If not, see <http://www.gnu.org/licenses/>.
 */
package core.tasks;

import core.para.Para;
import core.rb.IB;
import core.tasks.pack.RPartPack;
import gui.processor.Processor;
import gui.utils.ProgBar;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class RPart {

    public RPart() {
    }

    public ArrayList<IB> part(ArrayList<String> rin, int minBin, Processor p) throws Exception {
        ArrayList<IB> fBins = new ArrayList<IB>();
        CountDownLatch cdl;
        ArrayList<String> seeds = new ArrayList<String>();
        ArrayList<String> reads = new ArrayList<String>();
        HashMap <String, Integer> hash = new HashMap <String, Integer>(250);
        String initSeed;
        ArrayList<String> bin;
        int noToSearch = (int) (rin.size() * ((double)Para.SD/100.00));
        int cutoff = rin.size() - noToSearch;
        DecimalFormat df = null;int startSize = rin.size();
        if(Para.GUI){
            p.dPrgA(ProgBar.START, noToSearch);        
        }
        else{df = new DecimalFormat("##.##");}
        
        do {
            initSeed = (String) rin.remove(0);
            bin = new ArrayList<String>();
            bin.add(initSeed);
            seeds.add(initSeed);
            do {
                for (String s : seeds) {
                    int size = rin.size() / Para.TRDS;
                    hash.clear();
                    for (int loc = 0; loc < (s.length() - 10); loc++){hash.put(s.substring(loc, loc + 10),  loc);}     
                    cdl = new CountDownLatch(Para.TRDS);
                    ArrayList <RPartPack> packs = new <RPartPack> ArrayList();
                    ExecutorService executorService = Executors.newFixedThreadPool(Para.TRDS);
                    for (int x = 0; x < Para.TRDS; x++) {
                        RPartPack ppp = new RPartPack(
                                            cdl,
                                            rin.subList((x * size), ((x * size) + size)),
                                            hash);
                        packs.add(ppp);
                        executorService.execute(ppp);
                    }
                    cdl.await();
                    executorService.shutdown();
                    for (RPartPack t : packs) {
                        reads.addAll(t.pOut);
                    }
                    rin.removeAll(Collections.singleton(null));
                }
                seeds.clear();
                if (reads.size() > Para.NOS) {
                    int step = reads.size() / Para.NOS;
                    for(int x=0; x<reads.size(); x += step){
                        seeds.add(reads.get(x));
                    }
                    bin.addAll(reads);
                    reads.clear();
                } else if (reads.size() > 0) {
                    seeds.addAll(reads);
                    bin.addAll(reads);
                    reads.clear();
                }
            } while (seeds.size() > 0);
            seeds.clear();
            if (bin.size() > minBin) {
                fBins.add(new IB(bin));
                if(Para.GUI){p.dPrgA(ProgBar.UPDATE, noToSearch - (rin.size() - cutoff));}
                else{System.out.print("\r partitioning: "+ df.format(100 - (((double)(rin.size()-cutoff)/(startSize-cutoff))) * 100) + "%");}
            }
        } while (rin.size() > cutoff);
        if(Para.GUI){
            p.dPrgA(ProgBar.END, 0);
        }
        else{{System.out.println("\n");}}
        return fBins;
    }
}